#include <stdio.h>
#include <unistd.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <pthread.h>
#include "CIpodLog.h"
#include "CIpodIap1.h"
#include "CIpodChip.h"
#include "CIpodEvent.h"
#include "CIpodVehicle.h"
#include "CIpodConfig.h"
#include "util/CStrTool.h"
#include "util/rgbtobmp.h"

const uint8 hidSupportLingoes   [] = {
    0x00, 0x03, 0x04, 0x0A
};

const uint8 sampleRate8000[]    = { 0x00, 0x00, 0x1f, 0x40 };
const uint8 sampleRate11025[]   = { 0x00, 0x00, 0x2B, 0x11 };
const uint8 sampleRate12000[]   = { 0x00, 0x00, 0x2E, 0xE0 };
const uint8 sampleRate16000[]   = { 0x00, 0x00, 0x3E, 0x80 };
const uint8 sampleRate22050[]   = { 0x00, 0x00, 0x56, 0x22 };
const uint8 sampleRate24000[]   = { 0x00, 0x00, 0x5D, 0xC0 };
const uint8 sampleRate32000[]   = { 0x00, 0x00, 0x7D, 0x00 };
const uint8 sampleRate44100[]   = { 0x00, 0x00, 0xAC, 0x44 };
const uint8 sampleRate48000[]   = { 0x00, 0x00, 0xBB, 0x80 };

CIpodIap1::CIpodIap1() {
    m_TransIDSupport = true;
    m_GlobalTransID = 1;
    sem_init(&m_WaitSem, 0, 0);
    pthread_mutex_init(&m_WaitMutex, NULL);
    m_ReponseGetAccessoryInfo = false;
    m_A2dpConnected = false;
    pthread_mutex_init(&m_ProctectMutex, NULL);
    m_BitmapPoint = 0;
    m_CurrentCategoryType = IPODCategoryType::ALL;
    m_NextCategoryType = IPODCategoryType::ALL;
    m_CategoryTypeIndex = 0;
    m_DBReset = false;
    m_SupportAllCategory = false;
    pthread_mutex_init(&m_ListMutex, NULL);
}

CIpodIap1::~CIpodIap1() {
    sem_destroy(&m_WaitSem);
    pthread_mutex_destroy(&m_WaitMutex);
    pthread_mutex_destroy(&m_ProctectMutex);
    pthread_mutex_destroy(&m_ListMutex);
}

int CIpodIap1::init(int connMode) {
    CIpodLog::i("CIpodIap1::init\n");

    int ret = -1;
    uint8 ack = IPOD_ACK_SUCCESS;
    RECEIVE_DATA_S recvData;
    ret = startIDPS(&ack);
    if (ret == 0) {
        if (ack == IPOD_ACK_BAD_PARAMETER) {
            CIpodLog::i("CIpodIap1::init, the iPod is not support IDSP, use identifyDeviceLingoes\n");
            ret = identifyDeviceLingoes(0x01, 0x00, 0x00, 0x01);
            if (ret == -1) {
                CIpodLog::e("CIpodIap1::init, identifyDeviceLingoes ERROR!\n");
                return -1;
            }
            m_ReponseGetAccessoryInfo = true;
            for (uint8 i = 0; i < sizeof(hidSupportLingoes); i++) {
                ret = getOptionForLingo(IPOD_LINGOS(hidSupportLingoes[i]), &m_OptionsForLingo[hidSupportLingoes[i]]);
                if (ret != 0x00) {
                    break;
                }
            }
            ret = identifyDeviceLingoes(IPOD_LINGO_FLAG_GENERAL | IPOD_LINGO_FLAG_EXTENDED_INTERFACE | IPOD_LINGO_FLAG_DIGITAL_AUDIO | IPOD_LINGO_FLAG_DISPLAY_REMOTE, 0x02, 0x200, 0x01);
        } else if (ack == IPOD_ACK_SUCCESS) {
            requestTransportMaxPayloadSize();
            for (uint8 i = 0; i < sizeof(hidSupportLingoes); i++) {
                ret = getOptionForLingo(IPOD_LINGOS(hidSupportLingoes[i]), &m_OptionsForLingo[hidSupportLingoes[i]]);
                if (ret != 0x00) {
                    break;
                }
            }
            if (ret != -1) {
                ret = setFIDTokenValues();
            }
            if (ret != -1) {
                ret = endIDPS();
            }
        } else {
            CIpodLog::e("CIpodIap1::init, startIDPS return a error ack. Please check the ipod whether it is supported!\n");
            return -1;
        }
    }
    for (uint8 i = 0; i < 10; i++) {
        ret = waitResponse(2000);

        if (ret == -1) {
            CIpodLog::e("CIpodIap1::init, start authentication has no ack!\n");
            return -1;
        }
        getResponseData(&recvData);
        if (recvData.commandID == GL_GET_ACC_AUTH_INFO) {
            ret = retAccessoryAuthInfo(recvData.transID);
        } else if (recvData.commandID == GL_GET_ACC_AUTH_SIGN) {
            ret = retAccessoryAuthSignature(recvData.transID);
            if (ret != -1) {
                break;
            }
        }
    }
    if (ret != -1) {
        ret = setParam();
    }
    if (ret != -1) {
        CIpodEvent::sendEvent(IPOD_EVT_MEDIA_UPDATE_PROGRESS, getHandle(), 100);
    }
    return ret;
}

int CIpodIap1::deinit() {
    CIpodLog::i("CIpodIap1::deinit\n");

    int ret = -1;
    ret = identifyDeviceLingoes(0x01, 0x00, 0x00, 0x01);
    if (ret == -1) {
        CIpodLog::e("CIpodIap1::deinit, identifyDeviceLingoes ERROR !\n");
    }
    int value = 0;
    sem_getvalue(&m_WaitSem, &value);
    if (value == 0) {
        sem_post(&m_WaitSem);
    }
    return 0;
}

int CIpodIap1::packetProc(const uint8 *data, uint16 len, bool native) {
    uint8 lingoID = 0;
    uint16 commandID = 0;
    uint16 transID = 0;
    uint16 point = 0;
    uint16 recvLen = 0;
    uint16 payloadLen = 0;
    uint16 packetLen = 0;
    if (data[0] != 0x55) {
        return -1;
    }
    recvLen = data[1];
    point = 2;
    if (recvLen == 0x00) {
        recvLen = (uint16)(data[2] << 8) + data[3];
        point = 4;
        packetLen = recvLen + 7;
    } else {
        packetLen = recvLen + 5;
    }
    lingoID = data[point];
    if (lingoID == SL_EXTENDED_INTERFACE) {
        commandID = (uint16)(data[point + 1] << 8) + data[point + 2];
    } else {
        commandID = data[point + 1];
    }
    if (isAckPacket(lingoID, commandID)) {
        if (lingoID == SL_GENERAL) {
            if (recvLen == 0x04 || recvLen == 0x08) {
                m_TransIDSupport = false;
            }
        }
    }

    if (m_TransIDSupport) {
        if (lingoID == SL_EXTENDED_INTERFACE) {
            transID = (uint16)(data[point + 3] << 8) + data[point + 4];
            payloadLen = recvLen - 5;
            point += 5;
        } else {
            transID = (uint16)(data[point + 2] << 8) + data[point + 3];
            payloadLen = recvLen - 4;
            point += 4;
        }
    } else {
        transID = 0x00;
        if (lingoID == SL_EXTENDED_INTERFACE) {
            payloadLen = recvLen - 3;
            point += 3;
        } else {
            payloadLen = recvLen - 2;
            point += 2;
        }
    }
    CIpodLog::i("CIpodIap1::packetDeal, receive lingoID = %x, commandID = %x, transID = %d, point = %d\n", lingoID, commandID, transID, point);

    switch (lingoID) {
    case SL_GENERAL:
        switch (commandID) {
        case GL_IPOD_ACK:
        case GL_RET_EXT_INTERFACE_MODE:
        case GL_RET_TANS_MAX_PAYLOAD_SIZE:
        case GL_ACK_FID_TOKEN_VALUE:
        case GL_IDPS_STATUS:
        case GL_ACK_ACC_AUTH_INFO:
        case GL_ACK_ACC_AUTH_SIGN:
        case GL_RET_IPOD_OPTIONS_FOR_LINGO:
        case GL_RET_IPOD_PREFER:
        case GL_RET_SUPPORT_EVENT_NOTIFIY:
        case GL_RET_LINGO_PROTOC_VER:
        case GL_RET_NOW_PLAY_APP_NAME:
            postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
            break;
        case GL_RET_IPOD_AUTH_SIGNO:
            if (data[point + 2] == data[point + 3]) {
                ackAuthInfo(transID);
                postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
            }
            break;
        case GL_RET_IPOD_NAME:
        case GL_RET_IPOD_SOFT_SERIAL_NUM:
        case GL_RET_IPOD_SOFT_VERSION:
        case GL_GET_ACC_AUTH_INFO:
            postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
            break;
        case GL_GET_ACC_OPTION:
            retAccessoryInfo(*(data + point));
            break;
        case GL_GET_ACC_AUTH_SIGN:
            memcpy(m_AuthSignature, data + point, 20);
            postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
            break;
        case GL_OPEN_DATA_SESSION_FOR_PROT:
        case GL_CLOSE_DATA_SESSION:
        case GL_IPOD_DATA_TRANSFER:
            break;
        case GL_IPOD_NOTIFIY:
            CIpodLog::i("CIpodIap1::packetDeal, GL_IPOD_NOTIFIY data:(Notification Type is: %x)\n\t",data[6]);
            if (data[6] == 0x11) {
                uint8 value = data[20];
                bool a2dpConnected = false;
                if((value >> 4) & 1) {
                    CIpodLog::i("CIpodIap1::packetDeal, A2DP CONNECTED!\n");
                    a2dpConnected = true;
                } else {
                    CIpodLog::i("CIpodIap1::packetDeal, A2DP DISCONNECTED!\n");
                    a2dpConnected = false;
                }
                if (a2dpConnected != m_A2dpConnected) {
                    m_A2dpConnected = a2dpConnected;
                    CIpodEvent::sendEvent(IPOD_EVT_A2DP_STATUS_CHANGED, getHandle(), m_A2dpConnected);
                }
            }
            break;
        case GL_SET_ACC_STATUS_NOTIFIY:
            retAccessoryStatusNotification(transID);
            accessoryStatusNotification(CIpodVehicle::getBtStatus());
            break;
        default:
            break;
        }
        break;
    case SL_EXTENDED_INTERFACE:
        switch (commandID) {
        case EIL_IPOD_ACK:
        case EIL_RET_CURRENT_PLAYING_TRACK_CHAPTERINFO:
        case EIL_ReturnIndexedPlayingTrackInfo:
        case EIL_RETURN_PLAY_STATUS:
        case EIL_RET_NUMBER_CATEGORIZED_DBRECORDS:
        case EIL_RETURN_CATEGORIZED_DBRECORDS:
        case EIL_RET_PLAYING_TRACK_INDEX:
        case EIL_ReturnNumPlayingTracks:
        case EIL_RET_INDEX_PLAYING_TRACK_TITLE:
        case EIL_RET_INDEX_PLAYING_TRACK_ARTIS_NAME:
        case EIL_RET_INDEX_PLAYING_TRACK_ALBUM_NAME:
        case EIL_RET_REPEAT:
        case EIL_RET_SHUFFLE:
        case EIL_RetArtworkFormats:
        case EIL_RET_TRACK_ARTWORK_TIMES:
            postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
            break;
        case EIL_RetTrackArtworkData:
            if (data[point] == 0 && data[point + 1] == 0) {
                memset(&m_ArtworkData, 0, sizeof(ArtworkData));
                m_ArtworkData.cPixelFormat = data[point + 2];
                m_ArtworkData.sWidth = CStrTool::charpoint2short((char *) data + point + 3);
                m_ArtworkData.sHeight = CStrTool::charpoint2short((char *) data + point + 5);
                m_ArtworkData.sTopLeftX = CStrTool::charpoint2short((char *) data + point + 7);
                m_ArtworkData.sTopLeftY = CStrTool::charpoint2short((char *) data + point + 9);
                m_ArtworkData.sBottomRightX = CStrTool::charpoint2short((char *) data + point + 11);
                m_ArtworkData.sBottomRightY = CStrTool::charpoint2short((char *) data + point + 13);
                m_ArtworkData.uiRowSize = CStrTool::charpoint2int( (char *) data + point + 15);
                m_ArtworkData.uiTotalSize = (m_ArtworkData.uiRowSize) * (m_ArtworkData.sHeight);
                if(0 == payloadLen - 19) {
                    commandID = EIL_IPOD_ACK;
                    postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
                } else if (payloadLen - 19 < BITMAP_MAX_SIZE) {
                    memcpy(m_BitmapData, data + point + 19, payloadLen - 19);
                    m_BitmapPoint += payloadLen - 19;
                }
            } else {
                if (m_BitmapPoint + payloadLen - 2 < BITMAP_MAX_SIZE) {
                    memcpy(m_BitmapData + m_BitmapPoint, data + point + 2, payloadLen - 2);
                }
                m_BitmapPoint += payloadLen - 2;
                if (m_BitmapPoint >= m_ArtworkData.uiTotalSize) {
                    m_ArtworkData.pImageData = m_BitmapData;
                    postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
                    m_BitmapPoint = 0;
                }
            }
            break;
        case EIL_PLAY_STATUS_CHANGE_NOTIFICATION:
            dealWithStatusChangeNotification(data + point);
            break;
        default:
            break;
        }
        break;
    case SL_DIGITAL_AUDIO:
        switch (commandID) {
        case DAL_IPOD_ACK:
            postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
            break;
        case DAL_GET_ACC_SAMPLE_RATE_CAPS:
            retAccessorySampleRate(transID);
            break;
        case DAL_RET_TRACK_NEW_AUDIO_ATTR: {
            generalLingoAccessoryAck(lingoID, transID, 0x00, commandID);
            CIpodEvent::sendEvent(IPOD_EVT_SAMPLE_RATE_CHANGED, getHandle(), CStrTool::charpoint2int((char *) data + point));
            break;
        }
        default:
            break;
        }
        break;
    case SL_SIMPLE_REMOTE:
        switch (commandID) {
        case IPOD_SRL_iPodAck:
            postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
            break;
        default:
            break;
        }
        break;
    case SL_DISPLAY_REMOTE:
        switch (commandID) {
        case IPOD_DRL_iPodAck:
            postWaitSem(lingoID, commandID, transID, payloadLen, data + point);
            break;
        case IPOD_DRL_RemoteEventNotification:
            dealWithDisplayRemoteEventNotification(data + point);
            break;
        }
        break;
    default:
        break;
    }
    return packetLen;
}

int CIpodIap1::notifyBtStatus(bool connected) {
    CIpodLog::i("CIpodIap1::notifyBtStatus, connected = %d\n", connected);
    return accessoryStatusNotification(connected);
}

int CIpodIap1::notifyUSBAudioStatus(bool enabled) {
    CIpodLog::i("CIpodIap1::notifyUSBAudioStatus, not support!\n");
    return -1;
}

int CIpodIap1::sendMediaCommand(int command) {
    CIpodLog::i("CIpodIap1::sendMediaCommand, command = %d\n", command);

    IPODCommandCode cmdCode;
    switch (command) {
    case IPODMediaCommand::PLAYPAUSE:
        cmdCode = IPOD_CMD_PLAYPAUSE;
        break;
    case IPODMediaCommand::PLAY:
        cmdCode = IPOD_CMD_NEWPLAY;
        break;
    case IPODMediaCommand::PAUSE:
        cmdCode = IPOD_CMD_NEWPAUSE;
        break;
    case IPODMediaCommand::NEXT:
        cmdCode = IPOD_CMD_NEXTTRACK;
        break;
    case IPODMediaCommand::PREVIOUS:
//        cmdCode = IPOD_CMD_PREVIOUSTRACK;
		cmdCode = IPOD_CMD_PREVIOUS;
        break;
    case IPODMediaCommand::SEEK_FORWARD:
        cmdCode = IPOD_CMD_STARTFF;
        break;
    case IPODMediaCommand::SEEK_BACKWARD:
        cmdCode = IPOD_CMD_STARTREW;
        break;
    case IPODMediaCommand::SEEKEND:
        cmdCode = IPOD_CMD_ENDFFREW;
        break;
    case IPODMediaCommand::SHUFFLE:
        return setShuffleMode();
    case IPODMediaCommand::REPEAT:
        return setRepeatMode();
    }
    return setPlayStatus(cmdCode);
}

int CIpodIap1::sendMediaCommandDown(int command) {
	CIpodLog::i("CIpodIap1::sendMediaCommandDown, command = %d\n", command);

    IPODCommandCode cmdCode;
    switch (command) {
    case IPODMediaCommand::PLAYPAUSE:
        cmdCode = IPOD_CMD_PLAYPAUSE;
        break;
    case IPODMediaCommand::PLAY:
        cmdCode = IPOD_CMD_NEWPLAY;
        break;
    case IPODMediaCommand::PAUSE:
        cmdCode = IPOD_CMD_NEWPAUSE;
        break;
    case IPODMediaCommand::NEXT:
        cmdCode = IPOD_CMD_NEXTTRACK;
        break;
    case IPODMediaCommand::PREVIOUS:
//        cmdCode = IPOD_CMD_PREVIOUSTRACK;
		cmdCode = IPOD_CMD_PREVIOUS;
        break;
    case IPODMediaCommand::SEEK_FORWARD:
        cmdCode = IPOD_CMD_STARTFF;
        break;
    case IPODMediaCommand::SEEK_BACKWARD:
        cmdCode = IPOD_CMD_STARTREW;
        break;
    case IPODMediaCommand::SEEKEND:
        cmdCode = IPOD_CMD_ENDFFREW;
        break;
    case IPODMediaCommand::SHUFFLE:
        return setShuffleMode();
    case IPODMediaCommand::REPEAT:
        return setRepeatMode();
    }
    return setPlayStatus(cmdCode);
}

int CIpodIap1::sendMediaCommandUp(int command) {
	CIpodLog::i("CIpodIap1::sendMediaCommandUp, command = %d\n", command);
	return 0;
}

int CIpodIap1::sendMediaCommandLibraryInfo(void*mediaInfo) {
	CIpodLog::i("CIpodIap1::sendMediaCommandLibraryInfo\n");
	return 0;
}

int CIpodIap1::sendStartLocationInformation(int start) {
	CIpodLog::i("CIpodIap1::sendStartLocationInformation\n");
	return 0;
}

int CIpodIap1::sendStartDeviceTimeUpdate( ) {
	CIpodLog::i("CIpodIap1::sendStartDeviceTimeUpdate\n");
	return 0;
}

int CIpodIap1::sendCallStateUpdateInfo(void *callStateInfo) {
	CIpodLog::i("CIpodIap1::sendCallStateUpdateInfo\n");
	return 0;
}

int CIpodIap1::setPlayingTrackPosition(uint32 position) {
    CIpodLog::i("CIpodIap1::setPlayingTrackPosition, position = %lu\n", position);

    uint32 positionTemp = position * 1000;
    uint8 positionBuf[4] = { 0 };
    positionBuf[0] = (uint8)(positionTemp >> 24);
    positionBuf[1] = (uint8)(positionTemp >> 16);
    positionBuf[2] = (uint8)(positionTemp >> 8);
    positionBuf[3] = (uint8)(positionTemp);
    return displayRemoteSetStateInfo(IPOD_DR_STATUS_TRACK_POS_MS, positionBuf, 4);
}

int CIpodIap1::getShuffleMode(int *mode) {
    if (mode == NULL) {
        CIpodLog::e("CIpodIap1::getShuffleMode, mode is null\n");
        return -1;
    }

    int ret = -1;
    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 transID = m_GlobalTransID++;
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GET_SHUFFLE, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(1000, SL_EXTENDED_INTERFACE, EIL_RET_SHUFFLE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getShuffleMode, ipod ack error!\n");
        } else {
            *mode = recvData.buf[0];
            CIpodLog::i("CIpodIap1::getShuffleMode, mode = %d\n", *mode);
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getRepeatMode(int *mode) {
    if (mode == NULL) {
        CIpodLog::e("CIpodIap1::getRepeatMode, mode is null\n");
        return -1;
    }

    int ret = -1;
    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 transID = m_GlobalTransID++;
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GET_REPEAT, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(1000, SL_EXTENDED_INTERFACE, EIL_RET_REPEAT, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getRepeatMode, ipod ack error!\n");
        } else {
            *mode = recvData.buf[0];
            CIpodLog::i("IpodIap1::getRepeatMode, mode = %d\n", *mode);
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getPlayingTrackTitle(std::string &title) {
    int32 index;
    int ret = getCurrentPlayingTrackIndex(&index);
    if (ret == 0) {
        ret = getIndexedPlayingTrackTitle(index, title);
    }
    CIpodLog::i("CIpodIap1::getPlayingTrackTitle, title = %s\n", title.c_str());
    return ret;
}

int CIpodIap1::getPlayingTrackDuration(int * duration)
{
    return 0;
}

int CIpodIap1::getPlayingTrackAlbum(std::string &album) {
    int32 index;
    int ret = getCurrentPlayingTrackIndex(&index);
    if (ret == 0) {
        ret = getIndexedPlayingTrackAlbum(index, album);
    }
    CIpodLog::i("CIpodIap1::getPlayingTrackAlbum, album = %s\n", album.c_str());
    return ret;
}

int CIpodIap1::getPlayingTrackArtist(std::string &artist) {
    int32 index;
    int ret = getCurrentPlayingTrackIndex(&index);
    if (ret == 0) {
        ret = getIndexedPlayingTrackArtist(index, artist);
    }
    CIpodLog::i("CIpodIap1::getPlayingTrackArtist, artist = %s\n", artist.c_str());
    return ret;
}

int CIpodIap1::getPlayingTrackAlbumArtwork() {
    CIpodLog::i("CIpodIap1::getPlayingTrackAlbumArtwork\n");

    ArtworkFormat artworkFormat[10];
    uint32 artworkFormatLen = 0;
    uint16 formatID = 0;
    memset(artworkFormat, 0, sizeof(ArtworkFormat) * 10);

    int32 index;
    int ret = getCurrentPlayingTrackIndex(&index);
    if (ret != 0) {
        CIpodLog::i("CIpodIap1::getPlayingTrackAlbumArtwork, get current index failed\n");
        return -1;
    }

    getArtworkFormats(artworkFormat, &artworkFormatLen);
    if(artworkFormatLen <= 0) {
        CIpodLog::w("CIpodIap1::getPlayingTrackAlbumArtwork, artworkFormatLen = %d\n", artworkFormatLen);
        return -1;
    } else {
        uint32 i;
        for(i = 0; i < artworkFormatLen; i++) {
            if(artworkFormat[i].imageHeight == 128) {
                formatID = artworkFormat[i].formatID;
                break;
            }
        }
        if(artworkFormat[i].imageHeight != 128) {
            formatID = artworkFormat[artworkFormatLen-1].formatID;
        }
    }
    return getTrackArtworkData(formatID, index);
}

int CIpodIap1::getDeviceInformation(){
	return 0;
}

int CIpodIap1::getPlayStatus(IPODPlayStatus *status) {
    if (status == NULL) {
        CIpodLog::e("CIpodIap1::getPlayStatus, status is null\n");
        return -1;
    }

    static uint32 lastTickCount = 0;
    struct timeval tvs;
    gettimeofday(&tvs, NULL);
    uint32 start = ((uint32) tvs.tv_sec) * 1000 + (uint32) tvs.tv_usec / 1000;
    if(start - lastTickCount < 100 * 10) {
        CIpodLog::w("CIpodIap1::getPlayStatus, this_tickcount() = %d, lastTickCount = %d\n", start, lastTickCount);
        usleep(1000 * (1000 - start + lastTickCount));
    }
    uint16 packetSize = 0;
    int ret = -1;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GET_PLAY_STATUS, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(2000, SL_EXTENDED_INTERFACE, EIL_RETURN_PLAY_STATUS, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getPlayStatus, ipod ack error!\n");
        } else {
            status->track_length = CStrTool::charpoint2int((char *) recvData.buf) / 1000;
            status->track_position = CStrTool::charpoint2int((char *) recvData.buf + 4) / 1000;
            status->state = *((recvData.buf) + 8);
        }
    }
    gettimeofday(&tvs, NULL);
    lastTickCount = ((uint32) tvs.tv_sec) * 1000 + (uint32) tvs.tv_usec / 1000;
    pthread_mutex_unlock(&m_ProctectMutex);
    CIpodLog::i("CIpodIap1::getPlayStatus, length = %lu, position = %lu, state = %d\n", status->track_length, status->track_position, status->state);
    return ret;
}

int CIpodIap1::getPlayingTrackInfo(int32 *index, uint32 *count) {
    if (index == NULL || count == NULL) {
        CIpodLog::e("CIpodIap1::getPlayingTrackInfo, index or count is null\n");
        return -1;
    }

    int ret = getNumberPlayingTracks(count);
    if (ret == 0) {
        ret = getCurrentPlayingTrackIndex(index);
    }
    CIpodLog::i("CIpodIap1::getPlayingTrackInfo, index = %lu, count = %lu\n", index, count);
    return ret;
}

int CIpodIap1::getPlayingChapterInfo(int32 *index, uint32 *count) {
    if (index == NULL || count == NULL) {
        CIpodLog::e("CIpodIap1::getPlayingChapterInfo, index or count is null\n");
        return -1;
    }

    int ret = -1;
    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData;
    uint16 transID = m_GlobalTransID++;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GET_CURRENT_PLAYING_TRACK_CHAPTERINFO, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(1000, SL_EXTENDED_INTERFACE, EIL_RET_CURRENT_PLAYING_TRACK_CHAPTERINFO, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getPlayingChapterInfo, get ipod ret error!\n");
        } else {
            *index = CStrTool::charpoint2int((char *) recvData.buf);
            *count = CStrTool::charpoint2int((char *) recvData.buf + 4);
            CIpodLog::i("CIpodIap1::getPlayingChapterInfo, index = %d, count = %d\n", *index, *count);
        }
    }
    return ret;
}

int CIpodIap1::isListLevelSupported(bool *supported) {
    if (supported == NULL) {
        CIpodLog::e("CIpodIap1::isListLevelSupported, supported is null\n");
        return -1;
    }

    *supported = false;
    CIpodLog::i("CIpodIap1::isListLevelSupported, supported = %d\n", *supported);
    return 0;
}

int CIpodIap1::resetMusicList(uint32 *num) {
    if (num == NULL) {
        CIpodLog::e("CIpodIap1::resetMusicList, num is null\n");
        return -1;
    }

    int ret = -1;
    ret = resetDBSection();
    if (ret < 0) {
        return ret;
    }

    m_DBReset = true;
    m_CurrentCategoryType = IPODCategoryType::ALL;
    m_NextCategoryType = IPODCategoryType::ALL;
    m_CategoryTypeIndex = 0;
    for (uint8 i = 0; i < 5; i++) {
        m_CategoryTypeQueue[i] = IPODCategoryType::ALL;
    }
    ret = getNumberCategorizedDBRecords(num, m_CurrentCategoryType);
    if (ret < 0 && m_CurrentCategoryType == IPODCategoryType::ALL) {
        *num = 6;
        ret = 0;
    }
    if (ret == 0 && *num > 0) {
        if (m_CurrentCategoryType == IPODCategoryType::ALL) {
            if (*num > 8) {
                *num = 8;
            }
        }
    }
    CIpodLog::i("IpodIap1::resetMusicList, num = %lu\n", *num);
    return ret;
}

int CIpodIap1::selectMusicList(int32 index, int32 level, uint32 *num) {
    CIpodLog::i("CIpodIap1::selectMusicList, index = %ld, level = %ld\n", index, level);

    if (num == NULL) {
        CIpodLog::e("CIpodIap1::selectMusicList, num is null\n");
        return -1;
    }

    int ret = -1;
    pthread_mutex_lock(&m_ListMutex);
    if (!m_DBReset) {
        ret = resetDBSection();
        if (ret < 0) {
            pthread_mutex_unlock(&m_ListMutex);
            return ret;
        }
        m_DBReset = true;
    }

    switch (m_CurrentCategoryType) {
    case IPODCategoryType::ALL:
        m_NextCategoryType = index;
        break;
    case IPODCategoryType::PLAYLIST:
        m_NextCategoryType = IPODCategoryType::SONGS;
        break;
    case IPODCategoryType::ARTIST:
        m_NextCategoryType = IPODCategoryType::ALBUM;
        break;
    case IPODCategoryType::ALBUM:
        m_NextCategoryType = IPODCategoryType::SONGS;
        break;
    case IPODCategoryType::GENRE:
        m_NextCategoryType = IPODCategoryType::ARTIST;
        break;
    case IPODCategoryType::AUDIOBOOK:
        m_NextCategoryType = IPODCategoryType::AUDIOBOOK;
        break;
    default:
        m_NextCategoryType = IPODCategoryType::SONGS;
        break;
    }
    if (m_CurrentCategoryType == IPODCategoryType::ALL) {
        CIpodLog::i("CIpodIap1::selectMusicList, m_CurrentCategoryType = IPOD_CATEGORY_ALL, m_SupportAllCategory = %d \n", m_SupportAllCategory);
        if (m_SupportAllCategory == 0x00) {
            ret = selectDBRecord(m_CurrentCategoryType, index);
        }
        ret = 0;
    } else {
        CIpodLog::i("CIpodIap1::selectMusicList, m_CurrentCategoryType = %d, index = %d\n", m_CurrentCategoryType, index);
        if (index == -1 && m_CurrentCategoryType == IPODCategoryType::SONGS) {
            ret = 0;
        } else {
            ret = selectDBRecord(m_CurrentCategoryType, index);
        }
    }
    if (ret == 0) {
        if (index < 0) {
            m_CategoryTypeIndex--;
            if (m_CategoryTypeIndex < 0)
            {
                m_CategoryTypeIndex = 0;
            }
            m_CurrentCategoryType = m_CategoryTypeQueue[m_CategoryTypeIndex];
        } else {
            if (m_CurrentCategoryType != IPODCategoryType::SONGS) {
                m_CurrentCategoryType = m_NextCategoryType;
                m_CategoryTypeIndex++;
                if (m_CategoryTypeIndex >= 4)
                {
                    m_CategoryTypeIndex = 4;
                }
                m_CategoryTypeQueue[m_CategoryTypeIndex] = m_CurrentCategoryType;
            }
        }
    }
    CIpodLog::i("CIpodIap1::selectMusicList, m_CurrentCategoryType = %d, m_CategoryTypeIndex = %d\n", m_CurrentCategoryType, m_CategoryTypeIndex);
    ret = getNumberCategorizedDBRecords(num, m_CurrentCategoryType);
    if (ret < 0 && m_CurrentCategoryType == IPODCategoryType::ALL) {
        *num = 6;
        ret = 0;
    }
    if (ret == 0 && *num > 0) {
        if (m_CurrentCategoryType == IPODCategoryType::ALL) {
            if (*num > 8) {
                *num = 8;
            }
        }
    }
    pthread_mutex_unlock(&m_ListMutex);
    CIpodLog::i("CIpodIap1::selectMusicList, num = %lu\n", num);

    return ret;
}

int CIpodIap1::getMusicList(uint32 startIndex, uint32 readCount, IPODMusicList *musicList) {
    CIpodLog::i("CIpodIap1::getMusicList, startIndex = %lu, readCount = %lu\n", startIndex, readCount);

    if (musicList == NULL) {
        CIpodLog::e("CIpodIap1::getMusicList, musicList is null\n");
        return -1;
    }

    int ret = -1;
    static uint32 recordNum = 0;

    pthread_mutex_lock(&m_ListMutex);
    if (!m_DBReset) {
        ret = resetDBSection();
        if (ret < 0) {
            goto end;
        }
        m_DBReset = true;
    }

    ret = getNumberCategorizedDBRecords(&recordNum, m_CurrentCategoryType);
    CIpodLog::i("CIpodIap1::getMusicList, recordNum = %d ret= %d\n", recordNum,ret);

    if (ret < 0 && m_CurrentCategoryType == IPODCategoryType::ALL) {
        m_SupportAllCategory = 0;
        recordNum = 6;
        if (startIndex + readCount > recordNum) {
            readCount = recordNum - startIndex;
        }
        IPODMusicSource source[recordNum];
        memset(source, 0, sizeof(IPODMusicSource) * recordNum);
        source[0].index = IPODCategoryType::PLAYLIST;
        source[0].name = "Playlists";
        source[1].index = IPODCategoryType::ARTIST;
        source[1].name = "Artists";
        source[2].index = IPODCategoryType::ALBUM;
        source[2].name = "Albums";
        source[3].index = IPODCategoryType::GENRE;
        source[3].name = "Genres";
        source[4].index = IPODCategoryType::SONGS;
        source[4].name = "Songs";
        source[5].index = IPODCategoryType::COMPOSER;
        source[5].name = "Composers";

        musicList->size = readCount;
        musicList->totalnum = recordNum;
        musicList->categorytype = m_CurrentCategoryType;
        musicList->start = startIndex;
        musicList->end = startIndex + readCount - 1;
        musicList->level = -1;

        for (uint32 i = 0; i < readCount; i++) {
            IPODMusicSource tempsource;
            tempsource.index = i;
            tempsource.id = 0;
            tempsource.name = source[i].name;
            musicList->elements.push_back(tempsource);
        }
        ret = 0;
        goto end;
    }

    if (ret == 0 && recordNum > 0) {
        if (m_CurrentCategoryType == IPODCategoryType::ALL) {
            if (recordNum > 8) {
                recordNum = 8;
            }
        }
        if (startIndex + readCount > recordNum) {
            readCount = recordNum - startIndex;
        }

        if (readCount > 0) {
            if (m_CurrentCategoryType == IPODCategoryType::ALL) {
                ret = retrieveCategorizedDBRecords(m_CurrentCategoryType, startIndex + 1, readCount, musicList->elements);
                if (ret == 0) {
                    musicList->size = readCount;
                    musicList->totalnum = recordNum;
                    musicList->categorytype = m_CurrentCategoryType;
                    musicList->start = startIndex;
                    musicList->end = startIndex + readCount -1;
                    musicList->level = -1;
                    CIpodLog::i("CIpodIap1::getMusicList, m_CurrentCategoryType = IPOD_CATEGORY_ALL, size = %d, totalnum = %d, categorytype = %d, start = %d, end = %d\n", musicList->size, musicList->totalnum, musicList->categorytype, musicList->start, musicList->end);
                }
            } else {
                ret = retrieveCategorizedDBRecords(m_CurrentCategoryType, startIndex, readCount, musicList->elements);
                if (ret == 0) {
                    musicList->size = readCount;
                    musicList->totalnum = recordNum;
                    musicList->categorytype = m_CurrentCategoryType;
                    musicList->start = startIndex;
                    musicList->end = startIndex + readCount - 1;
                    musicList->level = -1;
                    CIpodLog::i("CIpodIap1::getMusicList, m_CurrentCategoryType != IPOD_CATEGORY_ALL, size = %d, totolnum = %d, categorytype = %d, start = %d, end = %d\n", musicList->size, musicList->totalnum, musicList->categorytype, musicList->start, musicList->end);
                }
            }
        }
    } else {
        musicList->size = 0;
        musicList->totalnum = 0;
        musicList->categorytype = m_CurrentCategoryType;
        musicList->start = startIndex;
        musicList->end = startIndex;
        musicList->level = -1;
    }
end:
    pthread_mutex_unlock(&m_ListMutex);
    return ret;
}

int CIpodIap1::getMusicList_c(uint32 startIndex, uint32 readCount, C_IPODMusicList *musicList) {
    CIpodLog::i("CIpodIap1::getMusicList, startIndex = %lu, readCount = %lu\n", startIndex, readCount);

    if (musicList == NULL) {
        CIpodLog::e("CIpodIap1::getMusicList, musicList is null\n");
        return -1;
    }

    int ret = -1;
    static uint32 recordNum = 0;

    pthread_mutex_lock(&m_ListMutex);
    if (!m_DBReset) {
        ret = resetDBSection();
        if (ret < 0) {
            goto end;
        }
        m_DBReset = true;
    }

    ret = getNumberCategorizedDBRecords(&recordNum, m_CurrentCategoryType);
    CIpodLog::i("CIpodIap1::getMusicList, recordNum = %d ret= %d\n", recordNum,ret);

    if (ret < 0 && m_CurrentCategoryType == IPODCategoryType::ALL) {
        m_SupportAllCategory = 0;
        recordNum = 6;
        if (startIndex + readCount > recordNum) {
            readCount = recordNum - startIndex;
        }
        IPODMusicSource source[recordNum];
        memset(source, 0, sizeof(IPODMusicSource) * recordNum);
        source[0].index = IPODCategoryType::PLAYLIST;
        source[0].name = "Playlists";
        source[1].index = IPODCategoryType::ARTIST;
        source[1].name = "Artists";
        source[2].index = IPODCategoryType::ALBUM;
        source[2].name = "Albums";
        source[3].index = IPODCategoryType::GENRE;
        source[3].name = "Genres";
        source[4].index = IPODCategoryType::SONGS;
        source[4].name = "Songs";
        source[5].index = IPODCategoryType::COMPOSER;
        source[5].name = "Composers";

        musicList->size = readCount;
        musicList->totalnum = recordNum;
        musicList->categorytype = m_CurrentCategoryType;
        musicList->start = startIndex;
        musicList->end = startIndex + readCount - 1;
        musicList->level = -1;

        for (uint32 i = 0; i < readCount; i++) {
            musicList->elements[i].index = i;
            musicList->elements[i].id = 0;
            memcpy(musicList->elements[i].name,source[i].name.c_str(),sizeof(source[i].name));
        }
        ret = 0;
        goto end;
    }

    if (ret == 0 && recordNum > 0) {
        if (m_CurrentCategoryType == IPODCategoryType::ALL) {
            if (recordNum > 8) {
                recordNum = 8;
            }
        }
        if (startIndex + readCount > recordNum) {
            readCount = recordNum - startIndex;
        }

        if (readCount > 0) {
            if (m_CurrentCategoryType == IPODCategoryType::ALL) {
                ret = retrieveCategorizedDBRecords_c(m_CurrentCategoryType, startIndex + 1, readCount, musicList->elements);
                if (ret == 0) {
                    musicList->size = readCount;
                    musicList->totalnum = recordNum;
                    musicList->categorytype = m_CurrentCategoryType;
                    musicList->start = startIndex;
                    musicList->end = startIndex + readCount -1;
                    musicList->level = -1;
                    CIpodLog::i("CIpodIap1::getMusicList, m_CurrentCategoryType = IPOD_CATEGORY_ALL, size = %d, totalnum = %d, categorytype = %d, start = %d, end = %d\n", musicList->size, musicList->totalnum, musicList->categorytype, musicList->start, musicList->end);
                }
            } else {
                ret = retrieveCategorizedDBRecords_c(m_CurrentCategoryType, startIndex, readCount, musicList->elements);
                if (ret == 0) {
                    musicList->size = readCount;
                    musicList->totalnum = recordNum;
                    musicList->categorytype = m_CurrentCategoryType;
                    musicList->start = startIndex;
                    musicList->end = startIndex + readCount - 1;
                    musicList->level = -1;
                    CIpodLog::i("CIpodIap1::getMusicList, m_CurrentCategoryType != IPOD_CATEGORY_ALL, size = %d, totolnum = %d, categorytype = %d, start = %d, end = %d\n", musicList->size, musicList->totalnum, musicList->categorytype, musicList->start, musicList->end);
                }
            }
        }
    } else {
        musicList->size = 0;
        musicList->totalnum = 0;
        musicList->categorytype = m_CurrentCategoryType;
        musicList->start = startIndex;
        musicList->end = startIndex;
        musicList->level = -1;
    }
end:
    pthread_mutex_unlock(&m_ListMutex);
    return ret;
}

int CIpodIap1::selectMusicPlayingList(int32 index) {
    CIpodLog::i("CIpodIap1::selectMusicPlayingList, not support!\n");
    return -1;
}

int CIpodIap1::getMusicPlayingList(uint32 startIndex, uint32 readCount, C_IPODMusicList *musicList) {
    CIpodLog::i("CIpodIap1::getMusicPlayingList, not support!\n");
    return -1;
}

int CIpodIap1::launchApp(const char *appBundleID) {
    CIpodLog::i("CIpodIap1::launchApp, not support!\n");
    return -1;
}

int CIpodIap1::sendEAData(const uint8 *data, uint16 len) {
    CIpodLog::i("CIpodIap1::sendEAData, not support!\n");
    return -1;
}

int CIpodIap1::setLocationInformation(const char *sentence) {
    CIpodLog::i("CIpodIap1::setLocationInformation, not support!\n");
    return -1;
}

int CIpodIap1::carPlayStartSession(int type){
    CIpodLog::i("CIpodIap1::carPlayStartSession, not support!\n");
    return -1;
}

int CIpodIap1::oOBBTPairingCompletionInformation(int resultCode){
    CIpodLog::i("CIpodIap1::oOBBTPairingCompletionInformation, not support!\n");
    return -1;
}

int CIpodIap1::bluetoothPairingAccessoryInformation(const char * inPairingDataP192,const char * inPairingDataP256){
    CIpodLog::i("CIpodIap1::bluetoothPairingAccessoryInformation, not support!\n");
    return -1;
}

int CIpodIap1::bluetoothPairingStatus( int success, const char * cancelReason){
    CIpodLog::i("CIpodIap1::bluetoothPairingStatus, not support!\n");
    return -1;
}

uint16 CIpodIap1::createIapPacket(uint8 lingoID, uint16 commandID, uint16 transID, const uint8 *buf, uint16 len, uint8 *desbuf) {
    assert(desbuf != NULL);

    uint16 point = 0;
    uint16 packetlen = 0;
    uint16 checksum = 0;

    if (lingoID == 0x04) {
        if (!m_TransIDSupport) {
            packetlen = 3 + len;
        } else {
            packetlen = 5 + len;
        }
    } else {
        if (!m_TransIDSupport) {
            packetlen = 2 + len;
        } else {
            packetlen = 4 + len;
        }
    }

    desbuf[point++] = 0x55;
    if (packetlen < 253) {
        desbuf[point++] = packetlen;
        packetlen += 3;
    } else {
        desbuf[point++] = 0x00;
        desbuf[point++] = (uint8)((packetlen >> 8) & 0xff);
        desbuf[point++] = (uint8)(packetlen & 0xff);
        packetlen += 5;
    }
    desbuf[point++] = lingoID;
    if (lingoID == 0x04) {
        desbuf[point++] = (uint8)((commandID >> 8) & 0xff);
        desbuf[point++] = (uint8)(commandID & 0xff);
    } else {
        desbuf[point++] = (uint8)(commandID & 0xff);
    }

    if (m_TransIDSupport) {
        desbuf[point++] = (uint8)((transID >> 8) & 0xff);
        desbuf[point++] = (uint8)(transID & 0xff);
    }
    memcpy(desbuf + point, buf, len);

    point += len;

    for (uint16 i = 1; i < packetlen - 1; i++) {
        checksum += desbuf[i];
    }
    desbuf[point] = (~((uint8) checksum)) + 1;
    return packetlen;
}

uint16 CIpodIap1::createFIDTokenIdentifyPacket(uint8 numLingoes, const uint8 *accessoryLingoes, uint32 deviceOption, uint32 deviceID, uint8 *desbuf) {
    assert(accessoryLingoes != NULL && desbuf != NULL);

    desbuf[0] = 11 + numLingoes;
    desbuf[1] = 0x00;
    desbuf[2] = 0x00;
    desbuf[3] = numLingoes;
    memcpy(desbuf + 4, accessoryLingoes, numLingoes);
    desbuf[4 + numLingoes]  = (uint8)(deviceOption >> 24 & 0xff);
    desbuf[5 + numLingoes]  = (uint8)(deviceOption >> 16 & 0xff);
    desbuf[6 + numLingoes]  = (uint8)(deviceOption >> 8 & 0xff);
    desbuf[7 + numLingoes]  = (uint8)(deviceOption & 0xff);
    desbuf[8 + numLingoes]  = (uint8)(deviceID >> 24 & 0xff);
    desbuf[9 + numLingoes]  = (uint8)(deviceID >> 16 & 0xff);
    desbuf[10 + numLingoes] = (uint8)(deviceID >> 8 & 0xff);
    desbuf[11 + numLingoes] = (uint8)(deviceID & 0xff);
    return (desbuf[0] + 1);
}

uint16 CIpodIap1::createFIDTokenAccessoryCapsPacket(const uint8 *accCapsBitmask, uint8 *desbuf)  {
    assert(accCapsBitmask != NULL && desbuf != NULL);

    desbuf[0] = 0x0a;
    desbuf[1] = 0x00;
    desbuf[2] = 0x01;
    memcpy(desbuf + 3, accCapsBitmask, 8);
    return (desbuf[0] + 1);
}

uint16 CIpodIap1::createFIDTokenAccessoryInfoPacket(uint8 accInfoType, uint8 accInfoLen, const char *accInfo, uint8 *desbuf) {
    assert(desbuf != NULL);

    desbuf[0] = accInfoLen + 3;
    desbuf[1] = 0x00;
    desbuf[2] = 0x02;
    desbuf[3] = accInfoType;
    memcpy(desbuf + 4, accInfo, accInfoLen);
    return desbuf[0] + 1;}

uint16 CIpodIap1::createAccessoryAckPacket(uint8 lingoID, uint16 transID, uint8 commandStatus, uint8 respondID, uint8 *desbuf) {
    uint8 data[2] = { commandStatus, respondID };
    uint16 packetlen = 0;
    switch (lingoID) {
    case SL_GENERAL:
        packetlen = createIapPacket(lingoID, GL_ACC_ACK, transID, data, 2, desbuf);
        break;
    case SL_DIGITAL_AUDIO:
        packetlen = createIapPacket(lingoID, DAL_ACC_ACK, transID, data, 2, desbuf);
        break;
    }
    return packetlen;
}

uint8 CIpodIap1::getAckID(uint8 lingoID) {
    uint8 ackID = 0;
    switch (lingoID) {
    case SL_GENERAL:
        ackID = GL_IPOD_ACK;
        break;
    case SL_EXTENDED_INTERFACE:
        ackID = EIL_IPOD_ACK;
        break;
    case SL_DIGITAL_AUDIO:
        ackID = DAL_IPOD_ACK;
        break;
    case SL_SIMPLE_REMOTE:
        ackID = IPOD_SRL_iPodAck;
        break;
    case SL_DISPLAY_REMOTE:
        ackID = IPOD_DRL_iPodAck;
        break;
    default:
        ackID = 1;
        break;
    }
    return ackID;
}

bool CIpodIap1::isAckPacket(uint8 lingoID, uint8 command) {
    int ackCommand = 0;
    switch (lingoID) {
    case SL_GENERAL:
        ackCommand = GL_IPOD_ACK;
        break;
    case SL_EXTENDED_INTERFACE:
        ackCommand = EIL_IPOD_ACK;
        break;
    case SL_DIGITAL_AUDIO:
        ackCommand = DAL_IPOD_ACK;
        break;
    default:
        ackCommand = 0;
        break;
    }
    return (command == ackCommand) ? true : false;
}

void CIpodIap1::postWaitSem(uint8 lingoID, uint16 commandID, uint16 transID, uint16 len, const uint8 *data) {
    CIpodLog::i("CIpodIap1::postWaitSem, lingoID = %x, commandID = %x, transID = %u, len = %u\n", lingoID, commandID, transID, len);

    fillWaitPacket(lingoID, commandID, transID, len, data);
    sem_post(&m_WaitSem);
}

void CIpodIap1::fillWaitPacket(uint8 lingoID, uint16 commandID, uint16 transID, uint16 len, const uint8 *data) {
    RECEIVE_DATA_S recvData;
    recvData.lingoID = lingoID;
    recvData.commandID = commandID;
    recvData.transID = transID;
    recvData.len = len;
    memcpy(recvData.buf, data, len);
    m_RecvDatas.push_back(recvData);
}

int CIpodIap1::getResponseData(RECEIVE_DATA_S *recvData) {
    int ret = -1;
    if (!m_RecvDatas.empty()) {
        memcpy(recvData, &(*(m_RecvDatas.begin())), sizeof(RECEIVE_DATA_S));
        m_RecvDatas.pop_front();
        ret = 0;
    }
    return ret;
}

int CIpodIap1::waitResponse(uint32 timeout) {
    struct timespec ts;
    struct timeval tvs,tve;
    int ret = -1;

    gettimeofday(&tvs, NULL);
    if (timeout == 0) {
        ret = sem_wait(&m_WaitSem);
    } else {
        int second = timeout / 1000;
        int nsecond = timeout % 1000 * 1000 * 1000 + tvs.tv_usec * 1000;
        ts.tv_sec = tvs.tv_sec + second;

        if (nsecond > 999999999) {
            ts.tv_nsec = nsecond - 1000000000;
            ts.tv_sec += 1;
        } else {
            ts.tv_nsec = nsecond;
        }
        gettimeofday(&tvs, NULL);
        ret = sem_timedwait(&m_WaitSem, &ts);
        gettimeofday(&tve, NULL);
        long start = ((long)tvs.tv_sec)*1000+(long)tvs.tv_usec/1000;
        long end = ((long)tve.tv_sec)*1000+(long)tve.tv_usec/1000;
        CIpodLog::i("CIpodIap1::waitResponse - Cost time: %ld s %ld ms, time_out = %d, ret = %d\n", (end-start)/1000,(end-start)%1000, timeout, ret);
    }
    return (isDeviceExist() && !isExiting()) ? ret : -1;
}

int CIpodIap1::waitAck(int timeout, uint8 lingoID, uint16 transID, RECEIVE_DATA_S *recvData) {
    if (isExiting()) {
        CIpodLog::i("CIpodIap1::waitAck, exiting without waiting for ack!\n");
        return 0;
    }
    int ret = -1;
    int nCount = 0;
    RECEIVE_DATA_S recvTemp;
    pthread_mutex_lock(&m_WaitMutex);
    uint8 ackID = getAckID(lingoID);
waitAckRetry:
    ret = waitResponse(timeout);
    if (ret != -1) {
        getResponseData(&recvTemp);
        memcpy(recvData, &recvTemp, sizeof(RECEIVE_DATA_S));
        if (m_TransIDSupport && recvData->transID != transID) {
            CIpodLog::w("CIpodIap1::waitAck, error! transID(%d) is mismatch, recived lingoID(%d), commandID(%x), transID(%d)!\n", transID, recvData->lingoID, recvData->commandID, recvData->transID);
            goto waitAckRetry;
        }
        if (recvData->commandID == ackID) {
            if (recvData->buf[0] != 0) {
                CIpodLog::w("CIpodIap1::waitAck, ACK param is not success, and param is :%d \n", recvData->buf[0]);
            }
            pthread_mutex_unlock(&m_WaitMutex);
            return recvData->buf[0];
        } else {
            CIpodLog::d("CIpodIap1::waitAck, lingoID = %d, transID = %d is not ack packet, and recived lingoID = %d, commandID = %x\n", lingoID, transID, recvData->lingoID, recvData->commandID);
            goto waitAckRetry;
        }
    } else {
        CIpodLog::w("CIpodIap1::waitAck, lingoID = %d, transID = %d, timeout = %d (%d)times\n", lingoID, transID, timeout, nCount + 1);
    }
    pthread_mutex_unlock(&m_WaitMutex);
    return ret;
}

int CIpodIap1::waitCommand(int timeout, uint8 lingoID, uint16 commandID, uint16 transID, RECEIVE_DATA_S *recvData) {
    if (isExiting()) {
        CIpodLog::i("CIpodIap1::waitCommand, exiting without waiting for command!\n");
        return 0;
    }
    int ret = -1;
    int nCount = 0;
    RECEIVE_DATA_S recvTemp;

    pthread_mutex_lock(&m_WaitMutex);
waitCommandRetry:
    ret = waitResponse(timeout);
    if (ret != -1) {
        getResponseData(&recvTemp);
        memcpy(recvData, &recvTemp, sizeof(RECEIVE_DATA_S));
        if (m_TransIDSupport && recvData->transID != transID) {
            CIpodLog::w("CIpodIap1::waitCommand, error! lingoID(%d), commandID(0x%x), transID(%d), and recived lingo_id(%d), commandID(0x%x), transID(%d)!\n", lingoID, commandID, transID, recvData->lingoID, recvData->commandID,recvData->transID);
            goto waitCommandRetry;
        }
        if (recvData->commandID == commandID && recvData->lingoID == lingoID) {
            pthread_mutex_unlock(&m_WaitMutex);
            return 0;
        } else {
            if (recvData->lingoID == lingoID && recvData->commandID == getAckID(lingoID)) {
                CIpodLog::w("CIpodIap1::waitCommand, [waited = reciver] lingoID = %d, commandID = 0x%x, transID = %d, And receive a ack packet\n", lingoID, commandID, transID);
                ret = -1;
                goto exit;
            }
            CIpodLog::w("CIpodIap1::waitCommand error! reciver (lingoID = %d, commandID = 0x%x, transID = %d)\n", recvData->lingoID, recvData->commandID, recvData->transID);
            CIpodLog::w("And the waited (lingoID = %d, commandID = 0x%x, transID = %d)\n", lingoID, commandID, transID);
            goto waitCommandRetry;
        }
    } else {
        CIpodLog::w("CIpodIap1::waitCommand, lingoID = %d, commandID = 0x%x, transID = %d, timeout = %d (%d)times\n", lingoID, commandID, transID, timeout, nCount + 1);
    }
exit:
    pthread_mutex_unlock(&m_WaitMutex);
    return ret;
}

int CIpodIap1::startIDPS(uint8 *ack) {
    CIpodLog::i("CIpodIap1::startIDPS\n");

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    m_TransIDSupport = true;
    packetSize = createIapPacket(SL_GENERAL, GL_START_IDPS, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitAck(2000, SL_GENERAL, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::startIDPS, ipod ack error!\n");
        } else {
            *ack = recvData.buf[0];
        }
    }
    return ret;
}

int CIpodIap1::endIDPS() {
    CIpodLog::i("IpodIap1::endIDPS\n");

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    uint8 status = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createIapPacket(SL_GENERAL, GL_END_IDPS, transID, &status, 1, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(1000, SL_GENERAL, GL_IDPS_STATUS, transID, &recvData);
        if (ret == -1) {
            CIpodLog::w("CIpodIap1::endIDPS, ipod ack error, and it can be ingored!\n");
        }
    }
    return ret;
}

int CIpodIap1::requestTransportMaxPayloadSize() {
    CIpodLog::i("CIpodIap1::requestTransportMaxPayloadSize\n");

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createIapPacket(SL_GENERAL, GL_REQ_TANS_MAX_PAYLOAD_SIZE, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(1000, SL_GENERAL, GL_RET_TANS_MAX_PAYLOAD_SIZE, transID, &recvData);
    }
    return ret;
}

int CIpodIap1::getOptionForLingo(IPOD_LINGOS lingoID, IAP_OPTIONS_FOR_LINGO *option) {
    CIpodLog::i("CIpodIap1::getOptionForLingo, lingoID = %x\n", lingoID);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[1] = { 0 };
    assert(option != NULL);
    buf[0] = lingoID;
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_GENERAL, GL_GET_IPOD_OPTIONS_FOR_LINGO, transID, buf, 1, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(1000, SL_GENERAL, GL_RET_IPOD_OPTIONS_FOR_LINGO, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getOptionForLingo, ipod ack error!\n");
        } else {
            option->lingo = IPOD_LINGOS(recvData.buf[0]);
            memcpy(option->option, recvData.buf + 1, 8);
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::setFIDTokenValues() {
    CIpodLog::i("CIpodIap1::setFIDTokenValues\n");

    int ret = -1;
    uint8 payloadBuf[1024] = { 0 };
    uint8 tempbuf[1024] = { 0 };
    uint16 packetSize = 0;
    uint16 point = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    payloadBuf[0] = 0x00;

    point = 1;
    packetSize = createFIDTokenIdentifyPacket(sizeof(hidSupportLingoes), (uint8 *)hidSupportLingoes, 0x00000002, 0x00000200, tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    uint8 data[8] = { 0 };
    data[7] = 0x10;
    data[6] = 0x00;
    data[5] = 0x00;
    packetSize = createFIDTokenAccessoryCapsPacket(data, tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    IPODIdentification *identification = CIpodConfig::getIdentification();

    packetSize = createFIDTokenAccessoryInfoPacket(0x01, identification->name.length() + 1, identification->name.c_str(), tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    memset(data, 0, 3);
    data[2] = 0x1;
    data[1] = 0x0;
    data[0] = 0x1;
    packetSize = createFIDTokenAccessoryInfoPacket(0x04, 3, (char *) data, tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    memset(data, 0, 3);
    data[2] = 0x2;
    data[1] = 0x0;
    data[0] = 0x1;
    packetSize = createFIDTokenAccessoryInfoPacket(0x05, 3, (char *) data, tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    packetSize = createFIDTokenAccessoryInfoPacket(0x06, identification->manufacturer.length() + 1, identification->manufacturer.c_str(), tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    packetSize = createFIDTokenAccessoryInfoPacket(0x07, identification->modelIdentifier.length() + 1, identification->modelIdentifier.c_str(), tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    packetSize = createFIDTokenAccessoryInfoPacket(0x08, identification->serialNumber.length() + 1, identification->serialNumber.c_str(), tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    data[3] = 0x02;
    data[2] = 0x00;
    data[1] = 0x00;
    data[0] = 0x00;
    packetSize = createFIDTokenAccessoryInfoPacket(0x0B, 4, (char *)data, tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    data[3] = 0x0;
    data[2] = 0x0;
    data[1] = 0x0;
    data[0] = 0x0;
    packetSize = createFIDTokenAccessoryInfoPacket(0x0C, 4, (char *)data, tempbuf);
    memcpy(payloadBuf + point, tempbuf, packetSize);
    point += packetSize;
    payloadBuf[0]++;

    packetSize = createIapPacket(SL_GENERAL, GL_SET_FID_TOKEN_VALUE, transID, payloadBuf, point, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(2000, SL_GENERAL, GL_ACK_FID_TOKEN_VALUE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::setFIDTokenValues, get ipod ack error!\n");
        }
    }
    return ret;
}

int CIpodIap1::identifyDeviceLingoes(uint32 lingoesSpoken, uint32 option, uint32 deviceID, uint32 optionFlag) {
    CIpodLog::i("CIpodIap1::identifyDeviceLingoes, lingoesSpoken = %lu, option = %lu, deviceID = %lu, optionFlag = %lu\n", lingoesSpoken, option, deviceID, optionFlag);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    uint8 buf[12] = { 0 };
    uint16 playloadLen = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    if (optionFlag == 1) {
        CStrTool::int2charpoint(lingoesSpoken, buf);
        CStrTool::int2charpoint(option, buf + 4);
        CStrTool::int2charpoint(deviceID, buf + 8);
        playloadLen = 12;
    } else {
        CStrTool::int2charpoint(lingoesSpoken, buf);
        CStrTool::int2charpoint(deviceID, buf + 4);
        playloadLen = 8;
    }

    m_TransIDSupport = false;
    packetSize = createIapPacket(SL_GENERAL, GL_INDENTIFY_DEV_LINGO, transID, buf, playloadLen, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitAck(2000, SL_GENERAL, transID, &recvData);
    }
    return ret;
}

int CIpodIap1::retAccessoryAuthInfo(uint16 transID) {
    CIpodLog::i("CIpodIap1::retAccessoryAuthInfo, transID = %u\n", transID);

    int ret = -1;
    uint16 certificateLen = 0;
    uint8 payloadBuf[2048] = { 0 };
    uint8 data[1024] = { 0 };
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 packetSize = 0;
    CIpodChip::recv(0x30, data, 2);
    certificateLen = (uint16)(data[0] << 8 & 0xff00) + (uint16)(data[1] & 0x00ff);

    uint8 certNum = 0;
    if (certificateLen % 128 == 0) {
        certNum = certificateLen / 128;
    } else {
        certNum = certificateLen / 128 + 1;
    }

    for (uint16 i = 0; i < certNum; i++) {
        payloadBuf[0] = 0x2;
        payloadBuf[1] = 0x0;
        payloadBuf[2] = i;
        payloadBuf[3] = certNum - 1;
        CIpodChip::recv(0x31 + i, data, 128);
        memcpy(payloadBuf + 4, data, 128);

        if (i < certNum - 1) {
            packetSize = createIapPacket(SL_GENERAL, GL_RET_ACC_AUTH_INFO, transID, payloadBuf, 128 + 4, iAPSendBuf);
        } else {
            packetSize = createIapPacket(SL_GENERAL, GL_RET_ACC_AUTH_INFO, transID, payloadBuf, certificateLen - 128 * i + 4, iAPSendBuf);
        }
        ret = send(iAPSendBuf, packetSize);
        if (ret != -1) {
            if (i < certNum - 1) {
                ret = waitAck(1000, SL_GENERAL, transID, &recvData);
                if (ret == -1) {
                    CIpodLog::e("CIpodIap1::retAccessoryAuthInfo, get ipod ack error!\n");
                    return -1;
                }
            } else {
                ret = waitCommand(1000, SL_GENERAL, GL_ACK_ACC_AUTH_INFO, transID, &recvData);
                if (ret == -1) {
                    CIpodLog::e("CIpodIap1::retAccessoryAuthInfo, get ipod GL_ACK_ACC_AUTH_INFO error!\n");
                    return -1;
                }
            }
        }
    }
    return ret;
}

int CIpodIap1::retAccessoryAuthSignature(uint16 transID) {
    CIpodLog::i("CIpodIap1::retAccessoryAuthSignature, transID = %u\n", transID);

    int ret = -1;
    uint16 packetSize = 0;
    uint8 temp2[2] = { 0 };
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    CIpodChip::send(0x21, m_AuthSignature, 20);
    temp2[0] = 1;
    CIpodChip::send(0x10, temp2, 1);

    for (uint8 i = 0; i < 10; i++) {
        usleep(350000);
        CIpodChip::recv(0x10, temp2, 1);
        if (temp2[0] != 0x10) {
            continue;
        } else {
            CIpodChip::recv(0x11, temp2, 2);
            uint16 signatureLen = (temp2[0] << 8 & 0xff00) + (temp2[1] & 0xff);
            CIpodChip::recv(0x12, m_SignatureData, signatureLen);
            packetSize = createIapPacket(SL_GENERAL, GL_RET_ACC_AUTH_SIGN, transID, m_SignatureData, 128, iAPSendBuf);
            ret = send(iAPSendBuf, packetSize);
            if (ret != -1) {
                ret = waitCommand(2000, SL_GENERAL, GL_ACK_ACC_AUTH_SIGN, transID, &recvData);
                if (ret == -1) {
                    CIpodLog::e("CIpodIap1::retAccessoryAuthSignature, get ipod GL_ACK_ACC_AUTH_INFO error!\n");
                    return -1;
                } else {
                    if (recvData.buf[0] == 0x00) {
                        CIpodLog::i("CIpodIap1::retAccessoryAuthSignature, iap1 authentication success!\n");
                    } else {
                        CIpodLog::i("CIpodIap1::retAccessoryAuthSignature, iap1 authentication not success, ret = %d!\n", recvData.buf[0]);
                        return -1;
                    }
                }
            }
            return ret;
        }
    }
    return -1;
}

int CIpodIap1::setParam() {
    CIpodLog::i("CIpodIap1::setParam\n");

    int ret = -1;
    uint64 eventNotificationMask = 0x00;
    uint64 eventNotificationMaskTemp = 0x00;

    ret = getSupportedEventNotification(&eventNotificationMask);
    CIpodLog::i("CIpodIap1::setParam, 1. eventNotificationMask = %lx\n", eventNotificationMask);
    eventNotificationMaskTemp = IPOD_NOTI_BITMASK_FLOW_CONTROL |
                                IPOD_NOTI_BITMASK_CHARGING_INFO |
                                IPOD_NOTI_BITMASK_DATABASE_CHANGED |
                                IPOD_NOTI_BITMASK_NOWPLAYINGFOCUSAPP_STATUS |
                                IPOD_NOTI_BITMASK_NOWPLAYINGAPPDISPLAYNAME_STATUS |
                                IPOD_NOTI_BITMASK_BT_CONNECTION_STATUS;
    eventNotificationMask = eventNotificationMaskTemp & eventNotificationMask;
    CIpodLog::i("CIpodIap1::setParam, 2. eventNotificationMask = %lx\n", eventNotificationMask);

    if (ret == 0) {
        setEventNotification(eventNotificationMask);
    }
    setAvailableCurrent(1000);

    if (m_TransIDSupport) {
        ret = setUIMode(IPOD_EXTENDED_INTERFACE_MODE);
        if (ret != 0) {
            ret = enterExtendedInterfaceMode();
            if (ret == 0) {
                ret = requestExtendedInterfaceMode();
            }
        }
    } else {
        ret = enterExtendedInterfaceMode();
    }

    setPlayStatusChangedNotification(IPOD_EVT_BASIC_PLAY_STATUS | IPOD_EVT_TRACK_CAPABILITIES_CHANGED | IPOD_EVT_TRACK_INDEX);
    setRemoteEventNotification(IPOD_DRE_PLAY_STATUS | IPOD_DRE_SHUFLE_SETTING | IPOD_DRE_REPEAT_SETTING | IPOD_DRE_TRACK_TIME_POS_SEC);
    return ret;
}

int CIpodIap1::getSupportedEventNotification(uint64 *data)
{
    CIpodLog::i("CIpodIap1::getSupportedEventNotification\n");

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };

    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_GENERAL, GL_GET_SUPPORT_EVENT_NOTIFIY, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1)
    {
        ret = waitCommand(2000, SL_GENERAL, GL_RET_SUPPORT_EVENT_NOTIFIY, transID, &recvData);
        if (ret == -1)
        {
            CIpodLog::e("CIpodIap1::getSupportedEventNotification, ipod ack error!\n");
        }
        else
        {
            *data = CStrTool::charpoint2longlong((char *)recvData.buf);
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::setEventNotification(uint64 data)
{
    CIpodLog::i("CIpodIap1::setEventNotification\n");

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[8] = { 0 };

    buf[0] = (uint8)(data >> 56);
    buf[1] = (uint8)(data >> 48);
    buf[2] = (uint8)(data >> 40);
    buf[3] = (uint8)(data >> 32);
    buf[4] = (uint8)(data >> 24);
    buf[5] = (uint8)(data >> 16);
    buf[6] = (uint8)(data >> 8);
    buf[7] = (uint8)(data);
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_GENERAL, GL_SET_EVENT_NOTIFIY, transID, buf, 8, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1)
    {
        ret = waitAck(1000, SL_GENERAL, transID, &recvData);
        if (ret == -1)
        {
            CIpodLog::e("CIpodIap1::setEventNotification, ipod ack error!\n");
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::setAvailableCurrent(uint16 current)
{
    CIpodLog::i("CIpodIap1::setAvailableCurrent, current = %u\n", current);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[2] = { 0 };
    CStrTool::short2charpoint(current, buf);

    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_GENERAL, GL_SET_AVAILABLE_CURRENT, transID, buf, 2, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1)
    {
        ret = waitAck(2000, SL_GENERAL, transID, &recvData);
        if (ret == -1)
        {
            CIpodLog::e("CIpodIap1::setAvailableCurrent, ipod ack error!\n");
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::setUIMode(IPODUIMode uiMode)
{
    CIpodLog::i("CIpodIap1::setUIMode, uiMode = %d\n", uiMode);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createIapPacket(SL_GENERAL, GL_SET_UI_MODE, transID, (uint8 *)&uiMode, 1, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1)
    {
        ret = waitAck(1000, SL_GENERAL, transID, &recvData);
        if (ret == -1)
        {
            CIpodLog::e("CIpodIap1::setUIMode, get ipod ack error!\n");
        }
    }
    return ret;
}

int CIpodIap1::enterExtendedInterfaceMode()
{
    CIpodLog::i("CIpodIap1::enterExtendedInterfaceMode\n");

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    int waitTime = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createIapPacket(SL_GENERAL, GL_ENTER_EXTENDED_INTERFACE_MODE, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1)
    {
        ret = waitAck(3000, SL_GENERAL, transID, &recvData);
        if (ret == -1)
        {
            CIpodLog::e("CIpodIap1::enterExtendedInterfaceMode, get ipod ack error!\n");
        }
        if (recvData.buf[0] == 0x06)
        {
            waitTime = CStrTool::charpoint2int((char *)((recvData.buf) + 2));
            ret = waitAck(waitTime, SL_GENERAL, transID, &recvData);
            if (ret == 0)
            {
                CIpodLog::i("CIpodIap1::enterExtendedInterfaceMode, success! wait time = %d\n", waitTime);
            }
        }
    }
    return ret;
}

int CIpodIap1::requestExtendedInterfaceMode()
{
    CIpodLog::i("CIpodIap1::requestExtendedInterfaceMode\n");

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createIapPacket(SL_GENERAL, GL_REQ_EXT_INTERFACE_MODE, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1)
    {
        ret = waitCommand(1000, SL_GENERAL, GL_RET_EXT_INTERFACE_MODE, transID, &recvData);
        if (ret == -1)
        {
            CIpodLog::e("CIpodIap1::requestExtendedInterfaceMode, get ipod ret error!\n");
        }
        if (recvData.buf[0] == 0x00)
        {
            CIpodLog::e("CIpodIap1::requestExtendedInterfaceMode, ret error data = %d!\n", recvData.buf[0]);
        }
    }
    return ret;
}

int CIpodIap1::setPlayStatusChangedNotification(uint32 changeEvent)
{
    CIpodLog::i("CIpodIap1::setPlayStatusChangedNotification, changeEvent = %lu\n", changeEvent);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[4] = { 0 };
    CStrTool::int2charpoint(changeEvent, buf);

    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_REMOTE_UI_EXTENDED, EIL_SET_PLAY_STATUS_CHANGE_NOTIFICATION, transID, buf, 4, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1)
    {
        ret = waitAck(1000, SL_EXTENDED_INTERFACE, transID, &recvData);
        if (ret == -1)
        {
            CIpodLog::e("CIpodIap1::setPlayStatusChangedNotification, 1. ipod ack error!\n");
        }
        else if (recvData.buf[0] != 0)
        {
            CIpodLog::e("CIpodIap1::setPlayStatusChangedNotification, get nack! it means the ipod is old machine. Resend again\n");
            if (changeEvent != 0)
            {
                buf[0] = 1;
            }
            else
            {
                buf[0] = 0;
            }
            packetSize = createIapPacket(SL_REMOTE_UI_EXTENDED, EIL_SET_PLAY_STATUS_CHANGE_NOTIFICATION, transID, buf, 1, iAPSendBuf);
            ret = send(iAPSendBuf, packetSize);
            if (ret != -1)
            {
                ret = waitAck(1000, SL_EXTENDED_INTERFACE, transID, &recvData);
                if (ret == -1)
                {
                    CIpodLog::e("CIpodIap1::setPlayStatusChangedNotification, 2. ipod ack error!\n");
                    pthread_mutex_unlock(&m_ProctectMutex);
                    return -1;
                }
                else if (recvData.buf[0] != 0)
                {
                    CIpodLog::e("CIpodIap1::setPlayStatusChangedNotification, get nack!\n");
                    pthread_mutex_unlock(&m_ProctectMutex);
                    return -1;
                }
            }
        }
    }
    CIpodLog::i("CIpodIap1::setPlayStatusChangedNotification, success!!!!!!!!!!!!!!!!!!!!!\n");
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::setRemoteEventNotification(uint32 changeEvent)
{
    CIpodLog::i("CIpodIap1::setRemoteEventNotification, changeEvent = %lu\n", changeEvent);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[4] = { 0 };
    CStrTool::int2charpoint(changeEvent, buf);

    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_DISPLAY_REMOTE, IPOD_DRL_SetRemoteEventNotification, transID, buf, 4, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1)
    {
        ret = waitAck(1000, SL_DISPLAY_REMOTE, transID, &recvData);
        if (ret == -1)
        {
            CIpodLog::e("CIpodIap1::setRemoteEventNotification, ipod ack error!\n");
        }
        else if (recvData.buf[0] != 0)
        {
            CIpodLog::e("CIpodIap1::setRemoteEventNotification, get nack!\n");
            pthread_mutex_unlock(&m_ProctectMutex);
            return -1;
        }
    }
    CIpodLog::i("CIpodIap1::setRemoteEventNotification, success!!!!!!!!!!!!!!!!!!!!!\n");
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::ackAuthInfo(uint16 transID) {
    CIpodLog::i("CIpodIap1::ackAuthInfo, transID = %u\n", transID);

    uint8 ackResult = 0;
    uint16 packetSize = 0;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createIapPacket(SL_GENERAL, GL_ACK_IPOD_AUTH_SIGN, transID, &ackResult, 1, iAPSendBuf);
    return send(iAPSendBuf, packetSize);
}

int CIpodIap1::retAccessoryInfo(uint8 infoType) {
    CIpodLog::i("CIpodIap1::retAccessoryInfo, infoType = %u\n", infoType);

    uint8 payloadBuf[128] = { 0 };
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 payloadLen = 0;
    uint16 transID = 0;
    uint16 packetSize = 0;
    payloadBuf[0] = (uint8) infoType;
    if (!m_ReponseGetAccessoryInfo) {
        return -1;
    }
    IPODIdentification *identification = CIpodConfig::getIdentification();
	 CIpodLog::i("CIpodIap1::getIdentification(), identification = %d\n", identification);
    switch (infoType) {
        case ACCESSORY_INFO_CAPABITITILES:
            payloadBuf[1] = 0x00;
            payloadBuf[2] = 0x00;
            payloadBuf[3] = 0x03;
            payloadBuf[4] = 0xF3;
            payloadLen = 5;
            break;
        case ACCESSORY_NAME: {
            payloadLen = identification->name.length() + 1;
            memcpy(payloadBuf + 1, identification->name.c_str(), payloadLen);
            break;
        }
        case ACCESSORY_MIN_SUPPORT_IPOD_FIRMWARE_VERSION:
            break;
        case ACCESSORY_MIN_SUPPORT_LINGO_VERSION:
            break;
        case ACCESSORY_FIRMWARE_VERSION:
            payloadBuf[1] = 0x09;
            payloadBuf[2] = 0x08;
            payloadBuf[3] = 0x07;
            payloadLen = 4;
            break;
        case ACCESSORY_HARDWARE_VERSION:
            payloadBuf[1] = 0x01;
            payloadBuf[2] = 0x02;
            payloadBuf[3] = 0x03;
            payloadLen = 4;
            break;
        case ACCESSORY_MANUFACTURER: {
            payloadLen = identification->manufacturer.length() + 1;
            memcpy(payloadBuf + 1, identification->manufacturer.c_str(), payloadLen);
            break;
        }
        case ACCESSORY_MODEL_NUMBER: {
            payloadLen = identification->modelIdentifier.length() + 1;
            memcpy(payloadBuf + 1, identification->modelIdentifier.c_str(), payloadLen);
            break;
        }
        case ACCESSORY_SERIAL_NUMBER: {
            payloadLen = identification->serialNumber.length() + 1;
            memcpy(payloadBuf + 1, identification->serialNumber.c_str(), payloadLen);
            break;
        }
        case ACCESSORY_INCOMING_MAX_PAYLOAD_SIZE:
            payloadBuf[1] = 0x04;
            payloadBuf[2] = 0x00;
            payloadLen = 3;
            break;
        case ACCESSORY_STATUS_TYPE_SUPPORTED:
            break;
        default:
            break;
    }
    packetSize = createIapPacket(SL_GENERAL, GL_RET_ACC_OPTION, transID, (uint8 *)payloadBuf, payloadLen, iAPSendBuf);
    return send(iAPSendBuf, packetSize);
}

int CIpodIap1::retAccessoryStatusNotification(uint16 transID) {
    CIpodLog::i("CIpodIap1::retAccessoryStatusNotification, transID = %u\n", transID);

    int ret = -1;
    uint16 packetSize = 0;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[4] = { 0 };
    buf[3] = 0x02;
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_GENERAL, GL_RET_ACC_STATUS_NOTIFIY, transID, buf, 4, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::accessoryStatusNotification(bool connected) {
    CIpodLog::i("CIpodIap1::accessoryStatusNotification, connected = %d\n", connected);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[37] = { 0 };
    buf[0] = 0x01;
    buf[4] = 0x01;
    buf[8] = connected ? 0x01 : 0x00;
    memcpy(buf + 31, CIpodVehicle::getBtAddress(), 6);

    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_GENERAL, GL_ACC_STATUS_NOTIFIY, transID, buf, 37, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::retAccessorySampleRate(uint16 transID) {
    CIpodLog::i("CIpodIap1::retAccessorySampleRate, transID = %u\n", transID);

    std::list<int> rates = CIpodConfig::getIdentification()->usbDeviceTransport.rates;
    uint8 rateArray[rates.size() * 4];
    int rateArrayLen = 0;
    for (std::list<int>::iterator iter = rates.begin(); iter != rates.end(); ++iter)
    {
        int rate = *iter;
        switch (rate)
        {
        case IPODSampleRate::RATE_8000HZ:
            memcpy(rateArray + rateArrayLen, sampleRate8000, 4);
            rateArrayLen += 4;
            break;
        case IPODSampleRate::RATE_11025HZ:
            memcpy(rateArray + rateArrayLen, sampleRate11025, 4);
            rateArrayLen += 4;
            break;
        case IPODSampleRate::RATE_12000HZ:
            memcpy(rateArray + rateArrayLen, sampleRate12000, 4);
            rateArrayLen += 4;
            break;
        case IPODSampleRate::RATE_16000HZ:
            memcpy(rateArray + rateArrayLen, sampleRate16000, 4);
            rateArrayLen += 4;
            break;
        case IPODSampleRate::RATE_22050HZ:
            memcpy(rateArray + rateArrayLen, sampleRate22050, 4);
            rateArrayLen += 4;
            break;
        case IPODSampleRate::RATE_24000HZ:
            memcpy(rateArray + rateArrayLen, sampleRate24000, 4);
            rateArrayLen += 4;
            break;
        case IPODSampleRate::RATE_32000HZ:
            memcpy(rateArray + rateArrayLen, sampleRate32000, 4);
            rateArrayLen += 4;
            break;
        case IPODSampleRate::RATE_44100HZ:
            memcpy(rateArray + rateArrayLen, sampleRate44100, 4);
            rateArrayLen += 4;
            break;
        case IPODSampleRate::RATE_48000HZ:
            memcpy(rateArray + rateArrayLen, sampleRate48000, 4);
            rateArrayLen += 4;
            break;
        }
    }

    CIpodLog::i("CIpodIap1::retAccessorySampleRate, rates.size() = %d, rateArrayLen = %d", rates.size(), rateArrayLen);
    uint16 packetSize = 0;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createIapPacket(SL_DIGITAL_AUDIO, DAL_RET_ACC_SAMPLE_RATE_CAPS, transID, rateArray, rateArrayLen, iAPSendBuf);
    return send(iAPSendBuf, packetSize);
}

int CIpodIap1::generalLingoAccessoryAck(uint8 lingoID, uint16 transID, uint8 ackStatus, uint8 ackCommandID) {
    CIpodLog::i("CIpodIap1::generalLingoAccessoryAck, lingoID = %u, transID = %u, ackStatus = %u, ackCommandID = %u\n", lingoID, transID, ackStatus, ackCommandID);

    uint16 packetSize = 0;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    packetSize = createAccessoryAckPacket(lingoID, transID, ackStatus, ackCommandID, iAPSendBuf);
    return send(iAPSendBuf, packetSize);
}

int CIpodIap1::dealWithStatusChangeNotification(const uint8 *data) {
    CIpodLog::i("IpodIap1::dealWithStatusChangeNotification\n");

    switch (*data) {
        case TRACKCHANGED:
            CIpodEvent::sendEvent(IPOD_EVT_TRACK_CHANGED, getHandle(), CStrTool::charpoint2int((char *)(data + 1)));
            break;
        case TRACKTIME_OFFSET_MS:
        case CHAPTERINDEX:
        case TRACKTIME_OFFSET_S:
        case CHAPTER_TIME_OFFSET_MSEC:
        case CHAPTER_TIME_OFFSET_SEC:
        case TRACK_CAPABILITIES_CHANGED:
        case PLAYBACK_ENGINE_CONTNENTS_CHANGED:
        case TRACK_PLAYBACK_MODE:
        case PLAYBACK_STATUS_EXT:
        default:
            break;
    }
    return 0;
}

int CIpodIap1::dealWithDisplayRemoteEventNotification(const uint8 *data) {
    CIpodLog::i("CIpodIap1::dealWithDisplayRemoteEventNotification\n");

    switch (*data) {
    case IPOD_DR_STATUS_REPEAT_SETTING:
        CIpodEvent::sendEvent(IPOD_EVT_REPEAT_MODE_CHANGED, getHandle(), (int)(*(data + 1)));
        break;
    case IPOD_DR_STATUS_SHUFFLE_SETTING:
        CIpodEvent::sendEvent(IPOD_EVT_SHUFFLE_MODE_CHANGED, getHandle(), (int)(*(data + 1)));
        break;
    case IPOD_DR_STATUS_PLAY_STATUS:
        CIpodEvent::sendEvent(IPOD_EVT_PLAYBACK_STATE_CHANGED, getHandle(), (int)(*(data + 1)));
        break;
    case IPOD_DR_STATUS_PLAYBACK_INDEX:
        CIpodEvent::sendEvent(IPOD_EVT_TRACK_CHANGED, getHandle(), CStrTool::charpoint2int((char *)(data + 1)));
        break;
    case IPOD_DR_STATUS_TRACK_POS_S:
        CIpodEvent::sendEvent(IPOD_EVT_TRACK_POSITION_CHANGED, getHandle(), CStrTool::charpoint2short((char *)(data + 1)));
        break;
    default:
        break;
    }
    return 0;
}

int CIpodIap1::setPlayStatus(int command) {
    CIpodLog::i("CIpodIap1::setPlayStatus command = %x\n", command);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_PLAY_CONTRAL, transID, (uint8 *) &command, 1, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitAck(2000, SL_EXTENDED_INTERFACE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::setPlayStatus, ipod ack error!\n");
        } else if (recvData.buf[0] != 0) {
            CIpodLog::e("CIpodIap1::setPlayStatus, get nack!\n");
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::setShuffleMode() {
    int ret = -1;
    int mode;
    ret = getShuffleMode(&mode);
    if (ret != 0) {
        CIpodLog::e("CIpodIap1::setShuffleMode, get current shuffle mode error!\n");
        return -1;
    }
    mode = (mode + 1) % 3;

    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 transID = m_GlobalTransID++;
    uint8 buf[2] = { 0 };
    buf[0] = mode;
    buf[1] = IPOD_RESTORE_ON_EXIT_STORED;
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_SET_SHUFFLE, transID, buf, 2, iAPSendBuf);
    pthread_mutex_lock(&m_ProctectMutex);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitAck(1000, SL_EXTENDED_INTERFACE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::setShuffleMode, ipod ack error!\n");
        } else if (recvData.buf[0] != 0) {
            CIpodLog::e("CIpodIap1::setShuffleMode, get nack!\n");
            ret = -1;
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::setRepeatMode() {
    int ret = -1;
    int mode;
    ret = getRepeatMode(&mode);
    if (ret != 0) {
        CIpodLog::e("CIpodIap1::setRepeatMode, get current repeat mode error!\n");
        return -1;
    }
    mode = (mode + 1) % 3;

    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 transID = m_GlobalTransID++;
    uint8 buf[2] = { 0 };
    buf[0] = mode;
    buf[1] = IPOD_RESTORE_ON_EXIT_STORED;
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_SET_REPEAT, transID, buf, 2, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitAck(1000, SL_EXTENDED_INTERFACE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::setRepeatMode, ipod ack error!\n");
        } else if (recvData.buf[0] != 0) {
            CIpodLog::e("CIpodIap1::setRepeatMode, get nack!\n");
            ret = -1;
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::displayRemoteSetStateInfo(IPOD_DR_STATUS_INFO statusInfo, const uint8 *infoData, uint16 dataLen) {
    CIpodLog::i("CIpodIap1::displayRemoteSetStateInfo, statusInfo = %x", statusInfo);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[10] = { 0 };
    buf[0] = statusInfo;
    if (dataLen < 9) {
        memcpy(buf + 1, infoData, dataLen);
    } else {
        CIpodLog::i("CIpodIap1::displayRemoteSetStateInfo, info data len > 9, overstep");
        return -1;
    }
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_DISPLAY_REMOTE, IPOD_DRL_SetiPodStateInfo, transID, buf, dataLen + 1, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitAck(1000, SL_DISPLAY_REMOTE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::displayRemoteSetStateInfo, ipod ack error!\n");
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getCurrentPlayingTrackIndex(int32 *index) {
    CIpodLog::i("CIpodIap1::getCurrentPlayingTrackIndex\n");

    int ret = -1;
    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData;
    uint16 tans_id = m_GlobalTransID++;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    assert(index != NULL);
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GET_PLAYING_TRACK_INDEX, tans_id, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(2000, SL_EXTENDED_INTERFACE, EIL_RET_PLAYING_TRACK_INDEX, tans_id, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getCurrentPlayingTrackIndex, ipod ack error!\n");
        } else {
            *index = CStrTool::charpoint2int((char *) recvData.buf);
            if (*index == 0xffffffff) {
                CIpodLog::i("CIpodIap1::getCurrentPlayingTrackIndex, RET 0xFFFFFFFF ,it mean now have no track play!\n");
                pthread_mutex_unlock(&m_ProctectMutex);
                return -1;
            }
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getIndexedPlayingTrackTitle(uint32 index, std::string &title) {
    CIpodLog::i("CIpodIap1::getIndexedPlayingTrackTitle, index = %lu\n", index);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[4] = { 0 };
    CStrTool::int2charpoint(index, buf);

    packetSize = createIapPacket(SL_REMOTE_UI_EXTENDED, EIL_GET_INDEX_PLAYING_TRACK_TITLE, transID, buf, 4, iAPSendBuf);
    pthread_mutex_lock(&m_ProctectMutex);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(2000, SL_EXTENDED_INTERFACE, EIL_RET_INDEX_PLAYING_TRACK_TITLE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getIndexedPlayingTrackName, ipod ack error!\n");
        } else {
            char tempstr[recvData.len];
            memcpy(tempstr, recvData.buf, recvData.len);
            title = tempstr;
            CIpodLog::i("CIpodIap1::getIndexedPlayingTrackName, title = %s\n", title.c_str());
            ret = 0;
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getIndexedPlayingTrackAlbum(uint32 index, std::string &album) {
    CIpodLog::i("CIpodIap1::getIndexedPlayingTrackAlbum, index = %lu\n", index);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[4] = { 0 };
    CStrTool::int2charpoint(index, buf);

    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_REMOTE_UI_EXTENDED, EIL_GET_INDEX_PLAYING_TRACK_ALBUM_NAME, transID, buf, 4, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(2000, SL_EXTENDED_INTERFACE, EIL_RET_INDEX_PLAYING_TRACK_ALBUM_NAME, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getIndexedPlayingTrackAlbum, ipod ack error!\n");
        } else {
            char tempstr[recvData.len];
            memcpy(tempstr, recvData.buf, recvData.len);
            album = tempstr;
            CIpodLog::i("CIpodIap1::getIndexedPlayingTrackAlbum, album = %s\n", album.c_str());
            ret =  0;
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getIndexedPlayingTrackArtist(uint32 index, std::string &artist) {
    CIpodLog::i("CIpodIap1::getIndexedPlayingTrackArtist, index = %lu\n", index);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[4] = { 0 };
    CStrTool::int2charpoint(index, buf);

    packetSize = createIapPacket(SL_REMOTE_UI_EXTENDED, EIL_GET_INDEX_PLAYING_TRACK_ARTIS_NAME, transID, buf, 4, iAPSendBuf);
    pthread_mutex_lock(&m_ProctectMutex);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(2000, SL_EXTENDED_INTERFACE, EIL_RET_INDEX_PLAYING_TRACK_ARTIS_NAME, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getIndexedPlayingTrackArtist, ipod ack error!\n");
        } else {
            char tempstr[recvData.len];
            memcpy(tempstr, recvData.buf, recvData.len);
            artist = tempstr;
            CIpodLog::i("CIpodIap1::getIndexedPlayingTrackArtist, artist = %s\n", artist.c_str());
            ret = 0;
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getArtworkFormats(pArtworkFormat artworkFormat, uint32 *formatLen) {
    CIpodLog::i("CIpodIap1::getArtworkFormats\n");

    int ret = -1;
    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 transID = m_GlobalTransID++;
    if (artworkFormat == NULL || formatLen == NULL) {
        CIpodLog::w("CIpodIap1::getArtworkFormats, artworkFormat or formatLen is NULL. artwork_format = %p, pformat_len = %p\n", artworkFormat, formatLen);
        return -1;
    }
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GetArtworkFormats, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(1000, SL_EXTENDED_INTERFACE, EIL_RetArtworkFormats, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getArtworkFormats, ipod ack error!\n");
            *formatLen = 0;
        } else {
            *formatLen = (recvData.len) / 7;
            for(uint32 i = 0; i < *formatLen; i++) {
                artworkFormat[i].formatID = CStrTool::charpoint2short(( char *)(recvData.buf + i * 7));
                artworkFormat[i].pixelFormat =recvData.buf[i * 7 + 2];
                artworkFormat[i].imageWidth = CStrTool::charpoint2short(( char *)(recvData.buf + i * 7 + 3));
                artworkFormat[i].imageHeight = CStrTool::charpoint2short(( char *)(recvData.buf + i * 7 + 5));
            }
            ret = 0;
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getTrackArtworkData(uint16 formatID, uint32 index) {
    CIpodLog::i("CIpodIap1::getTrackArtworkData, formatID = %u, index = %lu\n", formatID, index);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData = {0};
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[10] = { 0 };
    int timeOffset = 0;
    CStrTool::int2charpoint(index, buf);
    CStrTool::short2charpoint(formatID, buf + 4);
    CStrTool::int2charpoint(timeOffset, buf + 6);

    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GetTrackArtworkData, transID, buf, sizeof(buf), iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(4000, SL_EXTENDED_INTERFACE, EIL_RetTrackArtworkData, transID, &recvData);
        if (ret == -1) {
            if(recvData.commandID != EIL_IPOD_ACK) {
                CIpodLog::e("CIpodIap1::getTrackArtworkData, ipod ack error!\n");
            }

            memset(m_ArtworkPath, 0, sizeof(m_ArtworkPath));
            CIpodEvent::sendEvent(IPOD_EVT_ALBUM_ARTWORK_CHANGED, getHandle(), m_ArtworkPath);
        } else {
            memset(m_ArtworkPath, 0, sizeof(m_ArtworkPath));
            sprintf(m_ArtworkPath, "%s/album_artwork.bmp", CIpodVehicle::getCachePath());
            if (access(m_ArtworkPath, 0) == 0) {
                if (remove(m_ArtworkPath) == 0) {
                    CIpodLog::i("CIpodIap1::getTrackArtworkData, %s removed!\n", m_ArtworkPath);
                } else {
                    CIpodLog::i("CIpodIap1::getTrackArtworkData, %s remove error!\n", m_ArtworkPath);
                }
            }

            if (m_ArtworkData.uiTotalSize > 0) {
                save_rgb565_to_bmpfile(m_ArtworkData.pImageData, m_ArtworkData.sWidth, m_ArtworkData.sHeight, m_ArtworkPath);
            }

            CIpodEvent::sendEvent(IPOD_EVT_ALBUM_ARTWORK_CHANGED, getHandle(), m_ArtworkPath);
            ret = 0;
        }
    }

    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getNumberPlayingTracks(uint32 *count) {
    CIpodLog::i("CIpodIap1::getNumberPlayingTracks\n");

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    assert(count != NULL);
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GetNumPlayingTracks, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(2000, SL_EXTENDED_INTERFACE, EIL_ReturnNumPlayingTracks, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::getNumberPlayingTracks, ipod ack error!\n");
        } else {
            *count = CStrTool::charpoint2int((char *) recvData.buf);
            if (*count == 0x00) {
                CIpodLog::i("IpodIap1::getNumberPlayingTracks, RET 0x00, it mean now have no track play!\n");
            }
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::resetDBSection() {
    CIpodLog::i("CIpodIap1::resetDBSection\n");

    int ret = -1;
    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 transID = m_GlobalTransID++;
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_RESET_DB_SECTION, transID, NULL, 0, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitAck(3000, SL_EXTENDED_INTERFACE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::resetDBSection, ipod ack error!\n");
        } else if (recvData.buf[0] != 0) {
            CIpodLog::e("CIpodIap1::resetDBSection, get nack!\n");
        }
    } else {
        CIpodLog::e("CIpodIap1::resetDBSection, send error!\n");
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::getNumberCategorizedDBRecords(uint32 *recordNum, int type) {
    int ret = -1;
    uint16 packetSize = 0;
    RECEIVE_DATA_S recvData = {0};
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint16 transID = m_GlobalTransID++;
    assert(recordNum != NULL);
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_GET_NUMBER_CATEGORIZED_DBRECORDS, transID, (uint8 *) &type, 1, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitCommand(3000, SL_EXTENDED_INTERFACE, EIL_RET_NUMBER_CATEGORIZED_DBRECORDS, transID, &recvData);
        if (ret == -1) {
            if(recvData.commandID != EIL_IPOD_ACK) {
                CIpodLog::e("CIpodIap1::getNumberCategorizedDBRecords, ipod ack error!\n");
            }
        } else {
            *recordNum = CStrTool::charpoint2int((char *) recvData.buf);
            pthread_mutex_unlock(&m_ProctectMutex);
            return 0;
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    CIpodLog::i("CIpodIap1::getNumberCategorizedDBRecords, type = %d, recordNum = %lu\n", type, recordNum);
    return ret;
}

int CIpodIap1::selectDBRecord(int type, int32 index) {
    CIpodLog::i("CIpodIap1::selectDBRecord, type = %d, index = %ld\n", type, index);

    int ret = -1;
    uint16 packetSize = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 buf[5] = { 0 };
    buf[0] = type;
    CStrTool::int2charpoint(index, buf+1);

    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_REMOTE_UI_EXTENDED, EIL_SELECT_DB_SECTION, transID, buf, 5, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        ret = waitAck(3000, SL_EXTENDED_INTERFACE, transID, &recvData);
        if (ret == -1) {
            CIpodLog::e("CIpodIap1::selectDBRecord, ipod ack error!\n");
        } else if (recvData.buf[0] != 0) {
            CIpodLog::e("CIpodIap1::selectDBRecord, get nack, but still return 0 !\n");
            ret = 0;
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::retrieveCategorizedDBRecords(int type, uint32 startIndex, uint32 count, std::list<IPODMusicSource> &sourceList) {
    CIpodLog::i("CIpodIap1::retrieveCategorizedDBRecords, type = %d, startIndex = %lu, count = %lu\n", type, startIndex, count);

    uint16 packetSize = 0;
    int ret = -1;
    uint32 i = count, num = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 dataBuf[9] = { 0 };

    dataBuf[0] = type;
    CStrTool::int2charpoint(startIndex, dataBuf + 1);
    CStrTool::int2charpoint(count, dataBuf + 5);

    if (count <= 0) {
        CIpodLog::e("CIpodIap1::retrieveCategorizedDBRecords, count may <=0!");
        return -1;
    }
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_RETRIEVE_CATEGORIZED_DBRECORDS, transID, dataBuf, 9, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        while (i--) {
            ret = waitCommand(2000, SL_EXTENDED_INTERFACE, EIL_RETURN_CATEGORIZED_DBRECORDS, transID, &recvData);
            if (ret == -1) {
                CIpodLog::e("CIpodIap1::retrieveCategorizedDBRecords, ipod ack error!\n");
                return -1;
            } else {
                int index = CStrTool::charpoint2int((char *)(recvData.buf));
                num = index - startIndex;
                char namebuf[MAX_IAP_PACKET_LEN];
                strcpy(namebuf, (char *)(recvData.buf) + 4);
                IPODMusicSource source;
                source.index = index;
                source.id = 0;
                source.name = namebuf;
                sourceList.push_back(source);
                CIpodLog::i("CIpodIap1::retrieveCategorizedDBRecords, name-%d: %s\n", index, source.name.c_str());
            }
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}

int CIpodIap1::retrieveCategorizedDBRecords_c(int type, uint32 startIndex, uint32 count, C_IPODMusicSource *sourceList)
{
    CIpodLog::i("CIpodIap1::retrieveCategorizedDBRecords_c, type = %d, startIndex = %lu, count = %lu\n", type, startIndex, count);

    uint16 packetSize = 0;
    int ret = -1;
    uint32 i = count, num = 0;
    uint16 transID = m_GlobalTransID++;
    RECEIVE_DATA_S recvData;
    uint8 iAPSendBuf[MAX_IAP_PACKET_LEN] = { 0 };
    uint8 dataBuf[9] = { 0 };

    dataBuf[0] = type;
    CStrTool::int2charpoint(startIndex, dataBuf + 1);
    CStrTool::int2charpoint(count, dataBuf + 5);

    if (count <= 0) {
        CIpodLog::e("CIpodIap1::retrieveCategorizedDBRecords, count may <=0!");
        return -1;
    }
    pthread_mutex_lock(&m_ProctectMutex);
    packetSize = createIapPacket(SL_EXTENDED_INTERFACE, EIL_RETRIEVE_CATEGORIZED_DBRECORDS, transID, dataBuf, 9, iAPSendBuf);
    ret = send(iAPSendBuf, packetSize);
    if (ret != -1) {
        while (i--) {
            ret = waitCommand(2000, SL_EXTENDED_INTERFACE, EIL_RETURN_CATEGORIZED_DBRECORDS, transID, &recvData);
            if (ret == -1) {
                CIpodLog::e("CIpodIap1::retrieveCategorizedDBRecords, ipod ack error!\n");
                return -1;
            } else {
                int index = CStrTool::charpoint2int((char *)(recvData.buf));
                num = index - startIndex;
                char namebuf[MAX_IAP_PACKET_LEN];
                strcpy(namebuf, (char *)(recvData.buf) + 4);

                sourceList[count-i-1].index = index;
                sourceList[count-i-1].id = 0;
                memcpy(sourceList[count-i-1].name,namebuf,sizeof(namebuf));
                CIpodLog::i("CIpodIap1::retrieveCategorizedDBRecords, name-%d: %s\n", index, sourceList[count-i-1].name);
            }
        }
    }
    pthread_mutex_unlock(&m_ProctectMutex);
    return ret;
}
